package org.dant.ant.extension.net.processors;

import java.io.*;
import java.util.*;

import org.dant.apache.tools.ant.taskdefs.Execute;
import org.dant.ant.extension.types.Expect;
import org.dant.ant.extension.utils.StringUtils;
import org.dant.ant.extension.tasks.internal.RemoteResponse;
import org.dant.ant.extension.net.DefaultDispatcher;

public class CheckThread implements Runnable {

    protected Process process;

    protected List expectlist;
    protected RemoteResponse results;
  
    protected List expectFiles = new ArrayList();

    protected boolean succeed = true;
    protected File dir = null;

    protected Execute exe;
    protected String processKey;

    protected boolean blocking;

    protected ErrorChecker errchecker;
    protected OutputChecker outchecker;
  
    protected Thread errorThread;
    protected Thread outputThread;

    public CheckThread() {
        results = new RemoteResponse();
        errchecker = new ErrorChecker(this);
        outchecker = new OutputChecker(this);
    }

    public void setBlocking(boolean blocking) {
        this.blocking = blocking;
    }

    public void setProcessKey(String key) {
        this.processKey = key;
    }

    public void setExecute(Execute exe) {
        this.exe = exe;
    }

    public boolean isFinished() {
        return (errchecker.isFinished() && outchecker.isFinished());
    }

    public void setDir(File dir) {
        this.dir = dir;
    }

    public void shutdown() {
        if (errorThread.isAlive()) {
            System.out.println("Shuting down the std.err checker thread");
            errorThread.destroy();
        }
        if (outputThread.isAlive()) {
            System.out.println("Shuting down the std.out checker thread");
            outputThread.destroy();
        }
    }
  
    public void run() {
        try {
            check();
            join();
            notifyExe();
        } catch (Exception e){
            e.printStackTrace();
        }
    }

    public void join() throws InterruptedException {
        outputThread.join();
        errorThread.join();

        if (!errchecker.isFinished() || !outchecker.isFinished()) {
            System.out.println("The processing is succeed and it is finished now");
            if (!blocking) {
                System.out.println("And this process is not a blocking process, so we are going to destroy the process");
                DefaultDispatcher.getProcessRepository().remove(processKey, process);
            } else {
                System.out.println("And this process is a blocking process, ");
                System.out.println(" so you need to stop the process manually by <remotestop> task ");
                System.out.println(" or CTRL+C to stop all the processes lanunched by the daemon server");
            }
        }
    }

    private void setResults() {
        results.setSuccess(succeed);
        results.setStdErrBuffer(errchecker.getErrorBuffer());
        results.setStdOutBuffer(outchecker.getOutputBuffer());
    }
  
    protected void notifyExe() {
        setResults();
        synchronized(exe) {
            exe.notify();
        }
    }

    public boolean isSucceed() {
        return this.succeed;
    }

    public void setSucceed(boolean succeed) {
        this.succeed = succeed;
    }

    private void checkStdError(){
        errorThread = new Thread(errchecker);
        //    errorThread.setDaemon(true);
        errorThread.start();
    }

    private void checkStdOutput(){
        outputThread = new Thread(outchecker);
        //    outputThread.setDaemon(true);
        outputThread.start();
    }

    private void check() throws IOException {
        checkFiles();
        checkStdError();
        checkStdOutput();
    }

    private void checkFiles() {
        System.out.println("check files");
        for(Iterator iter=expectFiles.iterator(); iter.hasNext();) {
            File file = (File) iter.next();
            if (!file.exists()) {
                succeed = false;
                results.appendResult("Expected file: " + file + " is not exist");
                break;
            }
        }
    }

    public void setProcess(Process process) {
        this.process = process;
        setProcessInputStream(process.getInputStream());
        setProcessErrorStream(process.getErrorStream());
    }
  
    public void setProcessInputStream(InputStream is){
        outchecker.setProcessInputStream(is);
    }

    public void setProcessErrorStream(InputStream is){
        errchecker.setProcessErrorStream(is);
    }

    private void setupExpectStream() {
        for (Iterator iter=expectlist.iterator(); iter.hasNext();) {
            Expect expect =  (Expect) iter.next();
            File file = expect.getFile();
            if (file == null) {
                System.out.println("Expect Stream: " + expect.getText());
                if (expect.isErrStream()) {
                    errchecker.addExpectStream(expect.getText());
                } else {
                    outchecker.addExpectStream(expect.getText());
                }
            } else {
                String path = expect.getFile().toString();
                expectFiles.add(resolvePath(path));
                System.out.println(expectFiles.size() + " Expect Files:" + expect.getFile().toString());
            }
        }
    }
  
    public void setExpectList(List expectlist) {
        this.expectlist = expectlist;
        if (this.expectlist != null) 
            setupExpectStream();
        //    printExpectStream();
    }

    public void setResultsList(List resultsList) {
        if (resultsList != null)
            resultsList.add(results);
    }

    private File resolvePath(String path) {
        return new File(dir, path);
    }
}
